/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.mcx.modules.security.rest;

import com.mcx.annotation.rest.AnonymousGetMapping;
import com.mcx.exception.BadRequestException;
import com.mcx.modules.generation.service.AccountService;
import com.mcx.exception.handler.ApiSuccess;
import com.mcx.modules.generation.service.dto.AccountDto;
import com.mcx.modules.security.security.TokenProvider;
import com.mcx.modules.security.service.dto.AuthPhoneDto;
import com.mcx.modules.security.service.dto.JwtUserDto;
import com.mcx.modules.security.service.dto.OnlineUserDto;
import com.mcx.utils.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.mcx.annotation.rest.AnonymousDeleteMapping;
import com.mcx.annotation.rest.AnonymousPostMapping;
import com.mcx.modules.security.config.bean.LoginProperties;
import com.mcx.modules.security.config.bean.SecurityProperties;
import com.mcx.modules.security.service.OnlineUserService;
import com.mcx.modules.security.service.dto.AuthUserDto;
import com.mcx.utils.RedisUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Zheng Jie
 * @date 2018-11-23
 * 授权、根据token获取用户详细信息
 */
@Slf4j
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Api(tags = "系统：系统授权接口")
public class AuthorizationController {
    private final SecurityProperties properties;
    private final RedisUtils redisUtils;
    private final OnlineUserService onlineUserService;
    private final AccountService accountService;
    private final TokenProvider tokenProvider;
    @Resource
    private LoginProperties loginProperties;

    @ApiOperation("登录授权")
    @AnonymousPostMapping(value = "/login")
    public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception {
        if (accountService.countByUsernameAndPassword(authUser.getUsername(), authUser.getPassword()) != 1) {
            throw new BadRequestException("用户不存在或密码错误");
        }
        String token = tokenProvider.createToken(authUser);
        // 保存在线信息
        onlineUserService.save(authUser, token, request);
        // 返回 token 与 用户信息
        Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
            put("token", token);
            put("user", authUser);
        }};
        if (loginProperties.isSingleLogin()) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(authUser.getUsername(), token);
        }
        return new ResponseEntity<>(ApiSuccess.response(authInfo, "登录成功"), HttpStatus.OK);
    }

    @ApiOperation("登录授权")
    @AnonymousPostMapping(value = "/loginByPhone")
    public ResponseEntity<Object> loginByPhone(@Validated @RequestBody AuthPhoneDto authPhone, HttpServletRequest request) throws Exception {
        AccountDto accountDto = accountService.findByPhone(authPhone.getPhone());
        if (accountDto == null) {
            throw new BadRequestException("用户不存在");
        }
        AuthUserDto authUser = new AuthUserDto();
        authUser.setUsername(accountDto.getUsername());

        String token = tokenProvider.createToken(authUser);
        // 保存在线信息
        onlineUserService.save(authUser, token, request);
        // 返回 token 与 用户信息
        Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
            put("token", token);
            put("user", authUser);
        }};
        if (loginProperties.isSingleLogin()) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(authUser.getUsername(), token);
        }
        return new ResponseEntity<>(ApiSuccess.response(authInfo, "登录成功"), HttpStatus.OK);
    }

    @ApiOperation("获取用户信息")
    @GetMapping(value = "/info")
    public ResponseEntity<Object> getUserInfo(HttpServletRequest request) {
        String token = tokenProvider.getToken(request);
        if (token==null || token.equals("") || token.isEmpty() || token.equals("null")) {
            throw new BadRequestException("token为空");
        }
        OnlineUserDto userDto = onlineUserService.getOne(properties.getOnlineKey() + token);
        if(userDto == null){
            throw new BadRequestException("token已过期");
        }

        return ResponseEntity.ok(ApiSuccess.response(accountService.findByName(userDto.getUserName()), "获取用户信息成功", HttpStatus.OK));
    }

    @AnonymousGetMapping(value = "/check")
    public ResponseEntity<Object> check(HttpServletRequest request) {
        String token = tokenProvider.getToken(request);
        return ResponseEntity.ok(ApiSuccess.response(onlineUserService.getOne(properties.getOnlineKey() + token), "token可用", HttpStatus.OK));
    }

    @ApiOperation("退出登录")
    @AnonymousDeleteMapping(value = "/logout")
    public ResponseEntity<Object> logout(HttpServletRequest request) {
        onlineUserService.logout(tokenProvider.getToken(request));
        return new ResponseEntity<>(ApiSuccess.response("退出登录成功"), HttpStatus.OK);
    }
}
